package com.yugao.fintech.draper.scheduled.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yugao.fintech.draper.quartz.constants.ScheduleConstants;
import com.yugao.fintech.draper.quartz.scheduler.ScheduledJob;
import com.yugao.fintech.draper.scheduled.convert.QuartzJobConvert;
import com.yugao.fintech.draper.scheduled.dto.QuartzJobDTO;
import com.yugao.fintech.draper.scheduled.dto.QuartzJobQuery;
import com.yugao.fintech.draper.scheduled.entity.QuartzJob;
import com.yugao.fintech.draper.scheduled.mapper.QuartzJobMapper;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 定时任务调度表
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class QuartzJobService {
	private final QuartzJobMapper quartzJobMapper;
	private final ScheduledJob scheduledJob;

	public IPage<QuartzJobDTO> page(QuartzJobQuery queryVo) {
		LambdaQueryWrapper<QuartzJob> wrapper = Wrappers.<QuartzJob>lambdaQuery()
				.like(StrUtil.isNotBlank(queryVo.getJobName()), QuartzJob::getJobName, queryVo.getJobName());
		Page<QuartzJob> page = quartzJobMapper.selectPage(Page.of(queryVo.getPageNum(), queryVo.getPageSize()), wrapper);
		return QuartzJobConvert.INSTANCE.convertPage(page);
	}

	public QuartzJobDTO findById(Long id) {
		QuartzJob quartzJob = quartzJobMapper.selectById(id);
		return QuartzJobConvert.INSTANCE.convert(quartzJob);
	}

	/**
	 * 添加任务
	 */
	@SneakyThrows
	public QuartzJobDTO add(QuartzJobDTO quartzJobDto) {
		// 保存数据库
		quartzJobMapper.insert(QuartzJobConvert.INSTANCE.convert(quartzJobDto));
		// 创建定时任务
		scheduledJob.add(quartzJobDto.getJobId(), quartzJobDto.getJobGroup(), quartzJobDto.getParameters(), quartzJobDto.getJobName(), quartzJobDto.getCronExpression(), quartzJobDto.getMisfirePolicy());
		// 更改job状态
		changeStatus(quartzJobDto.getJobId(), quartzJobDto.getJobGroup(), quartzJobDto.getStatus());
		return quartzJobDto;
	}

	/**
	 * 更新任务
	 */
	@SneakyThrows
	public QuartzJobDTO update(QuartzJobDTO quartzJobDto) {
		quartzJobMapper.updateById(QuartzJobConvert.INSTANCE.convert(quartzJobDto));
		scheduledJob.update(quartzJobDto.getJobId(),
				quartzJobDto.getJobGroup(),
				quartzJobDto.getParameters(),
				quartzJobDto.getJobName(),
				quartzJobDto.getCronExpression(),
				quartzJobDto.getMisfirePolicy());
		// 更改job状态
		changeStatus(quartzJobDto.getJobId(), quartzJobDto.getJobGroup(), quartzJobDto.getStatus());
		return quartzJobDto;
	}

	/**
	 * 根据id删除任务
	 */
	@SneakyThrows
	public Boolean deleteByJobId(Long id) {
		QuartzJob quartzJob = quartzJobMapper.selectById(id);
		int count = quartzJobMapper.deleteById(id);
		if (count > 0) {
			scheduledJob.delete(quartzJob.getJobId(), quartzJob.getJobGroup());
		}
		return Boolean.TRUE;
	}

	/**
	 * 定时任务状态修改
	 */
	@SneakyThrows
	public Boolean changeStatus(QuartzJobDTO quartzJobDto) {
		// 更新数据库
		quartzJobMapper.updateById(QuartzJobConvert.INSTANCE.convert(quartzJobDto));
		// 更改job状态
		changeStatus(quartzJobDto.getJobId(), quartzJobDto.getJobGroup(), quartzJobDto.getStatus());
		return Boolean.TRUE;
	}

	private void changeStatus(Long jobId, String jobGroup, String status) {
		if (ScheduleConstants.Status.NORMAL.getValue().equals(status)) {
			resumeJob(jobId, jobGroup);
		}
		else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)) {
			pauseJob(jobId, jobGroup);
		}
	}

	/**
	 * 暂停任务
	 * @param jobId jobId
	 * @param jobGroup job分组
	 */
	public void pauseJob(Long jobId, String jobGroup) {
		scheduledJob.pause(jobId, jobGroup);
	}

	/**
	 * 恢复任务
	 * @param jobId jobId
	 * @param jobGroup job分组
	 */
	public void resumeJob(Long jobId, String jobGroup) {
		scheduledJob.resumeJob(jobId, jobGroup);
	}

	/**
	 * 定时任务立即执行一次
	 */
	@SneakyThrows
	public void run(QuartzJobDTO dto) {
		scheduledJob.trigger(dto.getJobId(), dto.getJobGroup());
	}

}